using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using TrackingSim.GameSystem;
using TrackingSim.GameSystem.Events;
using TrackingSim.GraphicSystem.Models;
using TrackingSim.GraphicSystem.Shaders;
using TrackingSim.ResourceSystem;
using TrackingSim.Filtering;


namespace TrackingSim
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        GraphicsDevice device;
        Effect effect;

        Matrix viewMatrix;
        Matrix projectionMatrix;
        Texture2D tex;

        List<Player> player_list;
        int currentPlayer;

        ResourceManager object_models_rm;
        ResourceManager shaders_rm;

        TimeSpan prev_marked_time;

        KeyboardState last_keyboard_state;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            prev_marked_time = new TimeSpan();
            last_keyboard_state = Keyboard.GetState();

            device = graphics.GraphicsDevice;

            device.RasterizerState = new RasterizerState
            {
                CullMode = CullMode.CullClockwiseFace
            };

            viewMatrix = Matrix.CreateLookAt(new Vector3(0f, 10f, -40f), new Vector3(0, 0, 0), new Vector3(0, 1, 0));

            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 0.2f, 1000.0f);

            createPlayers();

            currentPlayer = 0;

            base.Initialize();
        }

        private void createPlayers()
        {
            player_list = new List<Player>();

            TrackingSim.GameSystem.Plane p = null;

            p = new TrackingSim.GameSystem.Plane(new Vector3(0.0f, 0.0f, 0.0f),
                                                 new Vector3(0.0f, 0.0f, 1.0f),
                                                 new Vector3(0.0f, 1.0f, 0.0f));

            p.Speed = 0.001f;


            GameEventManager.registerForEvent(p, new GameSystem.Events.EventA());

            player_list.Add(p);

            p = new TrackingSim.GameSystem.Plane(new Vector3(20.0f, 5.0f, 20.0f),
                                                 new Vector3(-1.0f, 0.0f, 1.0f),
                                                 new Vector3(0.0f, 1.0f, 0.0f));

            p.Speed = 20.0f;
            p.MoveEnabled = true;

            player_list.Add(p);

            //GameEventManager.registerForEvent(p, new GameSystem.Events.EventA());
            //GameEventManager.registerForEvent(p, new GameSystem.Events.EventB());

            //GameEventManager.notifyObservers(new GameSystem.Events.EventA());
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            effect = Content.Load<Effect>("effects");
            tex = Content.Load<Texture2D>("heightmap");

            object_models_rm = new ResourceManager(ObjectModelLoader.Loader);
            shaders_rm = new ResourceManager(EffectLoader.Loader);

            object_models_rm.addResource("f22reg.obj");
            //object_models_rm.addResource("pod_racer2.obj");

            player_list[0].Model = (ObjectModel)object_models_rm.getResourceByName("f22reg");
            player_list[1].Model = (ObjectModel)object_models_rm.getResourceByName("f22reg");

            shaders_rm.addResource("effects");
        }

        private void DrawModel(string name)
        {

        }

        protected override void UnloadContent()
        {

        }

        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            KeyboardState ks = Keyboard.GetState();

            if (gameTime.TotalGameTime.TotalMilliseconds > prev_marked_time.TotalMilliseconds + 50)
            {
                double total_milliseconds = gameTime.TotalGameTime.TotalMilliseconds;

                Player current = player_list[currentPlayer % player_list.Count];

                //Move all of the players
                foreach (Player p in player_list)
                {
                    p.move(gameTime.ElapsedGameTime.Milliseconds);
                }


                //Take radar measurements
                TrackingSim.GameSystem.Plane current_plane = (TrackingSim.GameSystem.Plane)current;
                //foreach (Player p in player_list)
                //{
                //    if (p != current)
                //    {
                //        current_plane.run_se(p, gameTime.TotalGameTime.TotalSeconds);
                //    }
                //}

                //Take radar measurements
                TrackingSim.GameSystem.Plane plane_0 = (TrackingSim.GameSystem.Plane)player_list[0];
                plane_0.run_se(player_list[1], gameTime.TotalGameTime.TotalSeconds);

                prev_marked_time = gameTime.TotalGameTime;

                if (ks.IsKeyDown(Keys.Z))
                {
                    ++currentPlayer;
                }

                if (ks.IsKeyDown(Keys.X))
                {
                    current.resetPos();
                }

                if (ks.IsKeyDown(Keys.W))
                {
                    current.moveForward();
                }

                if (ks.IsKeyDown(Keys.S))
                {
                    current.moveBackward();
                }

                if (ks.IsKeyDown(Keys.A))
                {
                    current.turnLeft();
                }

                if (ks.IsKeyDown(Keys.D))
                {
                    current.turnRight();
                }

                if (ks.IsKeyDown(Keys.F))
                {
                    current.rollLeft();
                }

                if (ks.IsKeyDown(Keys.G))
                {
                    current.rollRight();
                }

                if (ks.IsKeyDown(Keys.Y))
                {
                    current.pitchUp();
                }

                if (ks.IsKeyDown(Keys.H))
                {
                    current.pitchDown();
                }

                if (ks.IsKeyDown(Keys.C))
                {
                    current.MoveEnabled = !current.MoveEnabled;
                }

                if (ks.IsKeyDown(Keys.R))
                {
                    current_plane.EnableRadar = !current_plane.EnableRadar;
                    current_plane.EnableTracker = !current_plane.EnableTracker;
                }

                if( ks.IsKeyDown(Keys.M))
                {
                    current_plane.print_logged_data();
                }
            }

            last_keyboard_state = ks;

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.DarkSlateBlue, 1000.0f, 0);

            foreach (Player p in player_list)
            {
                //p.WorldMatrix = p.Model.ModelToWorld * p.WorldMatrix;
                Matrix world = p.Model.ModelToWorld * p.WorldMatrix;

                Vector3 lightDirection = new Vector3(0, -10, 0);
                lightDirection.Normalize();

                effect.CurrentTechnique = effect.Techniques["Textured"];
                effect.Parameters["xWorld"].SetValue(world);
                effect.Parameters["xView"].SetValue(viewMatrix);
                effect.Parameters["xProjection"].SetValue(projectionMatrix);
                effect.Parameters["xTexture"].SetValue(tex);
                effect.Parameters["xEnableLighting"].SetValue(true);
                effect.Parameters["xLightDirection"].SetValue(lightDirection);
                effect.Parameters["xAmbient"].SetValue(0.5f);

                //BasicEffect basicEffect = new BasicEffect(device);
                //basicEffect.Alpha = 0.5f;
                //basicEffect.DiffuseColor = new Vector3(0.5f, 0.9f, 0.5f);
                //basicEffect.SpecularColor = new Vector3(0.25f, 0.25f, 0.25f);
                //basicEffect.SpecularPower = 5.0f;
                //basicEffect.AmbientLightColor = new Vector3(0.75f, 0.75f, 0.75f);

                //basicEffect.DirectionalLight0.Enabled = true; // enable each light individually
                //if (basicEffect.DirectionalLight0.Enabled)
                //{
                //    // x direction
                //    basicEffect.DirectionalLight0.DiffuseColor = new Vector3(1, 0, 0); // range is 0 to 1
                //    basicEffect.DirectionalLight0.Direction = Vector3.Normalize(new Vector3(-1, 0, 0));
                //    // points from the light to the origin of the scene
                //    basicEffect.DirectionalLight0.SpecularColor = Vector3.One;
                //}

                //basicEffect.DirectionalLight1.Enabled = true;
                //if (basicEffect.DirectionalLight1.Enabled)
                //{
                //    // y direction
                //    basicEffect.DirectionalLight1.DiffuseColor = new Vector3(0, 0.75f, 0);
                //    basicEffect.DirectionalLight1.Direction = Vector3.Normalize(new Vector3(0, -1, 0));
                //    basicEffect.DirectionalLight1.SpecularColor = Vector3.One;
                //}

                //basicEffect.LightingEnabled = true;

                //basicEffect.World = p.getWorldMatrix();
                //basicEffect.View = viewMatrix;
                //basicEffect.Projection = projectionMatrix;

                foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                {
                    pass.Apply();

                    p.Model.draw(device);
                    TrackingSim.GameSystem.Plane plane = (TrackingSim.GameSystem.Plane)p;
                    //plane.Tracker.draw_tracks(device);
                }

                world = Matrix.Identity;
                effect.Parameters["xWorld"].SetValue(world);

                foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                {
                    pass.Apply();

                    //p.Model.draw(device);
                    TrackingSim.GameSystem.Plane plane = (TrackingSim.GameSystem.Plane)p;
                    plane.Tracker.draw_tracks(device);
                }

            }

            base.Draw(gameTime);
        }
    }
}
